/* 
 * File:   main.cpp
 * Author: karthik
 *
 * Created on November 10, 2011, 9:42 AM
 */


#include <stdlib.h>
#include <iostream>
#include "string.h"
#include <stdio.h>
#include "helper.h"
#include "Pyramid.h"
#include "ApproximateMedian.h"
#include "Query.h"
#include <stx/btree.h>


#include <iostream>
using namespace std;
/*
 * 
 */



void failedArgs()
{
  cout << "Invalid Arguments.." << endl;
  cout << "\t check readme.txt file for more info" << endl;
}

void dumpArgs(int argc, char* argv[])
{
  cout << "argc = " << argc << endl;
  for(int i = 0; i < argc; i++)
  {
    cout << "argv[" << i << "] = '" << argv[i] << "'" << endl;
  }

}

int runArgs(int argc, char* argv[])
{
  //NOTE: strcmp equates {<, =, >}  which equals  {-1, 0, 1}

  //find and set all command args
  //NOTE: requires correct order:  {tree} {query}
  int argI = 1;
  bool configDone = false;
  bool treeDone = false;
  char fileName [100];
  
  Pyramid p;




  while(argI < argc)
  {
    const char * argT = argv[argI];

    if(strcmp(argT, "-BHM") == 0)//Build tree using Histogram median
    {
      if(argI+1 >= argc)
      {
          failedArgs();
          return 1;
      }


      argI++;
      const char * argTFile = argv[argI];
      int* fileInfo = getFileInfo(argTFile);


      //NOTE: that the data contains the id as the first value in each point
      double** data = readDataFile(argTFile, fileInfo[0], fileInfo[1]);

      if(data != NULL)
      {

          p.setdata(data,fileInfo[0],fileInfo[1]-1);

          strcpy(fileName,fileNamePrefix(argv[2]));
          strcat(fileName,".results");
          strcat(argv[2], ".txt");

          p.openOutFile(fileName);
          p.buildindexHM();
          p.buildtree();
          p.closeOutFile();

          strcpy(fileName,fileNamePrefix(argv[2]));
          strcat(fileName,".tree");
          strcat(argv[2], ".txt");

          p.openOutFile(fileName);
          p.savetree();
          p.closeOutFile();


          strcpy(fileName,fileNamePrefix(argv[2]));
          strcat(fileName,".median");
          strcat(argv[2], ".txt");
          p.openOutFile(fileName);
          p.savemedian();
          p.closeOutFile();

          treeDone = true;
      }
    }
    
    else if(strcmp(argT, "-BAM") == 0)//Build tree using Alogrithm
    {
      if(argI+1 >= argc)
      {
          failedArgs();
          return 1;
      }


      argI++;
      const char * argTFile = argv[argI];


      int* fileInfo = getFileInfo(argTFile);

      //NOTE: that the data contains the id as the first value in each point
      double** data = readDataFile(argTFile, fileInfo[0], fileInfo[1]);

      if(data != NULL)
      {

        p.setdata(data,fileInfo[0],fileInfo[1]-1);

        strcpy(fileName,fileNamePrefix(argv[2]));
        strcat(fileName,".results");
        strcat(argv[2], ".txt");

        p.openOutFile(fileName);
        p.buildindexAM();
        p.buildtree();
        p.closeOutFile();

        strcpy(fileName,fileNamePrefix(argv[2]));
        strcat(fileName,".tree");
        strcat(argv[2], ".txt");

        p.openOutFile(fileName);
        p.savetree();
        p.closeOutFile();


        strcpy(fileName,fileNamePrefix(argv[2]));
        strcat(fileName,".median");
        strcat(argv[2], ".txt");
        p.openOutFile(fileName);
        p.savemedian();
        p.closeOutFile();

        treeDone = true;

      }


    }
    else if(strcmp(argT, "-QPAM") == 0) //Do point query search, using approximate median
    {
      //ensure 1 arg plus tree done
      if(argI+1 >= argc || !treeDone)
      {
        failedArgs();
        return 1;
      }

      argI++;
      const char * argTFile = argv[argI];

      int* fileInfo = getFileInfo(argTFile);

      double** dataqp = readquerypointFile(argTFile, fileInfo[0], fileInfo[1]);

      strcpy(fileName,fileNamePrefix(argv[argI]));
      strcat(fileName,".results");
      strcat(argv[2], ".txt");

      p.openOutFile(fileName);
      p.searchquerypointsUAppM(dataqp,fileInfo[0]);
      p.closeOutFile();


    }

    else if(strcmp(argT, "-QRAM") == 0) //Do range query search, using approximate median
    {
      //ensure 1 arg plus tree done
      if(argI+1 >= argc || !treeDone)
      {
        failedArgs();
        return 1;
      }

      argI++;
      const char * argTFile = argv[argI];
      int* fileInfo = getFileInfo(argTFile);

      qr dataqr = readqueryrangeFile(argTFile, (fileInfo[0])/2, fileInfo[1]);

      strcpy(fileName,fileNamePrefix(argv[argI]));
      strcat(fileName,".results");
      strcat(argv[2], ".txt");

      p.openOutFile(fileName);
      p.searchqueryrangesUAppM(dataqr.min, dataqr.max, (fileInfo[0])/2);
      p.closeOutFile();

    }
    else if(strcmp(argT, "-QNAM") == 0) //Do KNN query search, using approximate median
    {
      //ensure 2 args plus tree done
      if(argI+2 >= argc || !treeDone)
      {
        failedArgs();
        return 1;
      }

      argI++;
      const char * argTFile = argv[argI];
      argI++;
      int k = atoi(argv[argI]);


      int* fileInfo = getFileInfo(argTFile);

      double** dataknn = readquerypointFile(argTFile, fileInfo[0], fileInfo[1]);

      strcpy(fileName,fileNamePrefix(argv[argI-1]));
      sprintf(fileName,"%s%d",fileName,k);
      strcat(fileName,".results");
      strcat(argv[2], ".txt");

      p.openOutFile(fileName);
      p.searchqueryKnnUAppM(dataknn,fileInfo[0],k);
      p.closeOutFile();

    }

    else if(strcmp(argT, "-BM") == 0)//Build tree using exact median
    {
      if(argI+1 >= argc)
      {
          failedArgs();
          return 1;
      }


      argI++;
      const char * argTFile = argv[argI];


      int* fileInfo = getFileInfo(argTFile);


      //NOTE: that the data contains the id as the first value in each point
      double** data = readDataFile(argTFile, fileInfo[0], fileInfo[1]);

      if(data != NULL)
      {

        p.setdata(data,fileInfo[0],fileInfo[1]-1);


        strcpy(fileName,fileNamePrefix(argv[2]));
        strcat(fileName,".results");
        strcat(argv[2], ".txt");

        p.openOutFile(fileName);
        p.buildindexM();
        p.buildtree();
        p.closeOutFile();

        strcpy(fileName,fileNamePrefix(argv[2]));
        strcat(fileName,".tree");
        strcat(argv[2], ".txt");

        p.openOutFile(fileName);
        p.savetree();
        p.closeOutFile();


        strcpy(fileName,fileNamePrefix(argv[2]));
        strcat(fileName,".median");
        strcat(argv[2], ".txt");
        p.openOutFile(fileName);
        p.savemedian();
        p.closeOutFile();

        treeDone = true;
      }


    }

    else if(strcmp(argT, "-QPM") == 0) //Do point query search, using exact median
    {
      //ensure 1 arg plus tree done
      if(argI+1 >= argc || !treeDone)
      {
        failedArgs();
        return 1;
      }

      argI++;
      const char * argTFile = argv[argI];
      int* fileInfo = getFileInfo(argTFile);

      double** dataqp = readquerypointFile(argTFile, fileInfo[0], fileInfo[1]);

      strcpy(fileName,fileNamePrefix(argv[argI]));
      strcat(fileName,".results");
      strcat(argv[2], ".txt");

      p.openOutFile(fileName);
      p.searchquerypointsUM(dataqp,fileInfo[0]);
      p.closeOutFile();


    }

    else if(strcmp(argT, "-QRM") == 0) //Do range query search, using exact median
    {
      //ensure 1 arg plus tree done
      if(argI+1 >= argc || !treeDone)
      {
        failedArgs();
        return 1;
      }

      argI++;
      const char * argTFile = argv[argI];

      int* fileInfo = getFileInfo(argTFile);

      struct qr dataqr = readqueryrangeFile(argTFile, (fileInfo[0])/2, fileInfo[1]);

      strcpy(fileName,fileNamePrefix(argv[argI]));
      strcat(fileName,".results");
      strcat(argv[2], ".txt");

      p.openOutFile(fileName);
      p.searchqueryrangesUM(dataqr.min, dataqr.max, (fileInfo[0])/2);
      p.closeOutFile();


    }
    else if(strcmp(argT, "-QNM") == 0) //Do KNN query search, using exact median
    {
      //ensure 2 args plus tree done
      if(argI+2 >= argc || !treeDone)
      {
        failedArgs();
        return 1;
      }

      argI++;
      const char * argTFile = argv[argI];
      argI++;
      int k = atoi(argv[argI]);

      int* fileInfo = getFileInfo(argTFile);

      double** dataknn = readquerypointFile(argTFile, fileInfo[0], fileInfo[1]);

      strcpy(fileName,fileNamePrefix(argv[argI-1]));
      sprintf(fileName,"%s%d",fileName,k);
      strcat(fileName,".results");
      strcat(argv[2], ".txt");

      p.openOutFile(fileName);
      p.searchqueryKnnUM(dataknn,fileInfo[0],k);
      p.closeOutFile();

    }


    else if(strcmp(argT, "-B") == 0 || strcmp(argT, "--build-tree") == 0) //build tree
    {
      //ensure 1 arg plus config done
      if(argI+1 >= argc)
      {
        failedArgs();
        return 1;
      }

     
      argI++;
      const char * argTFile = argv[argI];


      int* fileInfo = getFileInfo(argTFile);

      //NOTE: that the data contains the id as the first value in each point
      double** data = readDataFile(argTFile, fileInfo[0], fileInfo[1]);

      if(data != NULL)
      {

          p.setdata(data,fileInfo[0],fileInfo[1]-1);

          strcpy(fileName,fileNamePrefix(argv[2]));
          strcat(fileName,".results");
          strcat(argv[2], ".txt");


          p.openOutFile(fileName);
          p.buildindex();
          p.buildtree();
          p.closeOutFile();

          strcpy(fileName,fileNamePrefix(argv[2]));
          strcat(fileName,".tree");
          strcat(argv[2], ".txt");

          p.openOutFile(fileName);
          p.savetree();
          p.closeOutFile();


          strcpy(fileName,fileNamePrefix(argv[2]));
          strcat(fileName,".median");
          strcat(argv[2], ".txt");
          p.openOutFile(fileName);
          p.saveblankmedian();
          p.closeOutFile();

          treeDone = true;
      }

    }
    else if(strcmp(argT, "-S") == 0 || strcmp(argT, "--sequential-scan") == 0) //sequential scan
   {
	 //ensure 1 arg plus config done
	 if(argI+1 >= argc)
	 {
	   failedArgs();
	   return 1;
	 }


	 argI++;
	 const char * argTFile = argv[argI];


	 int* fileInfo = getFileInfo(argTFile);


	 //NOTE: that the data contains the id as the first value in each point
	 double** data = readDataFile(argTFile, fileInfo[0], fileInfo[1]);

	 if(data != NULL)
	 {

	   //cout <<"Data file loaded..." << endl;
	   p.setdata(data,fileInfo[0],fileInfo[1]-1);
	   p.buildSequentialScanData();

	   treeDone = true;
	 }

   }
    else if(strcmp(argT, "-L") == 0 || strcmp(argT, "--load-tree") == 0) //load tree
    {


        //ensure 1 arg plus config done
        if(argI+1 >= argc)
        {
          failedArgs();
          return 1;
        }


        argI++;
        const char * argTFile = argv[argI];


        int* fileInfo = getFileInfo(argTFile);


        //NOTE: that the data contains the id as the first value in each point
        double** data = readDataFile(argTFile, fileInfo[0], fileInfo[1]);

        if(data != NULL)
        {

          p.setdata(data,fileInfo[0],fileInfo[1]-1);


          strcpy(fileName,fileNamePrefix(argv[2]));
          strcat(fileName,".tree");
          strcat(argv[2], ".txt");
          //cout << "Tree Name:" << fileName << endl;
          p.openInFile(fileName);
          p.loadtree();
          p.closeInFile();

          strcpy(fileName,fileNamePrefix(argv[2]));
          strcat(fileName,".median");
          strcat(argv[2], ".txt");
          //cout << "Median Name:" << fileName << endl;
          p.openInFile(fileName);
          p.loadmedian();
          p.closeInFile();

          treeDone = true;
        }
    }
    else if(strcmp(argT, "-QP") == 0 || strcmp(argT, "--query-point") == 0) //load tree
    {
      //ensure 1 arg plus tree done
      if(argI+1 >= argc || !treeDone)
      {
        failedArgs();
        return 1;
      }

      argI++;
      const char * argTFile = argv[argI];

      int* fileInfo = getFileInfo(argTFile);

      double** dataqp = readquerypointFile(argTFile, fileInfo[0], fileInfo[1]);


      strcpy(fileName,fileNamePrefix(argv[argI]));
      strcat(fileName,".results");
      strcat(argv[2], ".txt");

      p.openOutFile(fileName);
      p.searchquerypoints(dataqp,fileInfo[0]);
      p.closeOutFile();
    }

    else if(strcmp(argT, "-QSP") == 0 || strcmp(argT, "--SSquery-point") == 0) //load tree
	{
	  //ensure 1 arg plus tree done
	  if(argI+1 >= argc || !treeDone)
	  {
		failedArgs();
		return 1;
	  }

	  argI++;
	  const char * argTFile = argv[argI];

	  int* fileInfo = getFileInfo(argTFile);

	  double** dataqp = readquerypointFile(argTFile, fileInfo[0], fileInfo[1]);

      strcpy(fileName,fileNamePrefix(argv[argI]));
      strcat(fileName,".results");
      strcat(argv[2], ".txt");

      p.openOutFile(fileName);
	  p.searchquerypointsSS(dataqp,fileInfo[0]);
	  p.closeOutFile();
	}
    else if(strcmp(argT, "-QR") == 0 || strcmp(argT, "--query-range") == 0) //load tree
    {
      //ensure 1 arg plus tree done
      if(argI+1 >= argc || !treeDone)
      {
        failedArgs();
        return 1;
      }

      argI++;
      const char * argTFile = argv[argI];

      int* fileInfo = getFileInfo(argTFile);

      struct qr dataqr = readqueryrangeFile(argTFile, (fileInfo[0])/2, fileInfo[1]);

      strcpy(fileName,fileNamePrefix(argv[argI]));
      strcat(fileName,".results");
      strcat(argv[2], ".txt");

      p.openOutFile(fileName);
      p.searchqueryranges(dataqr.min, dataqr.max, (fileInfo[0])/2);
      p.closeOutFile();
    }
    else if(strcmp(argT, "-QSR") == 0 || strcmp(argT, "--SSquery-range") == 0) //load tree
	{
	  //ensure 1 arg plus tree done
	  if(argI+1 >= argc || !treeDone)
	  {
		failedArgs();
		return 1;
	  }

	  argI++;
	  const char * argTFile = argv[argI];
	  int* fileInfo = getFileInfo(argTFile);

	  struct qr dataqr = readqueryrangeFile(argTFile, (fileInfo[0])/2, fileInfo[1]);


      strcpy(fileName,fileNamePrefix(argv[argI]));
      strcat(fileName,".results");
      strcat(argv[2], ".txt");

      p.openOutFile(fileName);
	  p.searchqueryrangesSS(dataqr.min, dataqr.max, (fileInfo[0])/2);
	  p.closeOutFile();

	}
    else if(strcmp(argT, "-QN") == 0 || strcmp(argT, "-query-knn") == 0) //load tree
    {
      //ensure 2 args plus tree done
      if(argI+2 >= argc || !treeDone)
      {
        failedArgs();
        return 1;
      }

      argI++;
      const char * argTFile = argv[argI];
      argI++;
      int k = atoi(argv[argI]);

      int* fileInfo = getFileInfo(argTFile);

      double** dataknn = readquerypointFile(argTFile, fileInfo[0], fileInfo[1]);

      strcpy(fileName,fileNamePrefix(argv[argI-1]));
      sprintf(fileName,"%s%d",fileName,k);
      strcat(fileName,".results");
      strcat(argv[2], ".txt");


      p.openOutFile(fileName);
      p.searchqueryKnn(dataknn,fileInfo[0],k);
      p.closeOutFile();
    }
    else if(strcmp(argT, "-QSN") == 0 || strcmp(argT, "-SSquery-knn") == 0) //load tree
        {
          //ensure 2 args plus tree done
          if(argI+2 >= argc || !treeDone)
          {
            failedArgs();
            return 1;
          }

          argI++;
          const char * argTFile = argv[argI];
          argI++;
          int k = atoi(argv[argI]);

          int* fileInfo = getFileInfo(argTFile);

          double** dataknn = readquerypointFile(argTFile, fileInfo[0], fileInfo[1]);

          strcpy(fileName,fileNamePrefix(argv[argI-1]));
          sprintf(fileName,"%s%d",fileName,k);
          strcat(fileName,".results");
          strcat(argv[2], ".txt");

          p.openOutFile(fileName);
          p.searchqueryKnnSS(dataknn,fileInfo[0],k);
          p.closeOutFile();

        }
    else //arg doesn't match anything
    {
      failedArgs();
      return 1;
    }
    argI++;

  } //end while loop on command args

}


int main(int argc, char** argv) {


     int retStatus = runArgs(argc, argv);

  //cout << "Program finished with status: " << retStatus << endl;

  return 0;

   
}

